{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=\"red\">注</font>: 使用 tensorboard 可视化需要安装 tensorflow (TensorBoard依赖于tensorflow库，可以任意安装tensorflow的gpu/cpu版本)\n",
    "\n",
    "```shell\n",
    "pip install tensorflow\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-25T06:54:07.251409900Z",
     "start_time": "2024-07-25T06:53:57.265381800Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:03.738087Z",
     "iopub.status.busy": "2025-01-24T02:03:03.737754Z",
     "iopub.status.idle": "2025-01-24T02:03:09.204539Z",
     "shell.execute_reply": "2025-01-24T02:03:09.203972Z",
     "shell.execute_reply.started": "2025-01-24T02:03:03.738064Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=10, micro=14, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.5.1+cu124\n",
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据准备\n",
    "\n",
    "https://www.kaggle.com/competitions/cifar-10/data\n",
    "\n",
    "```shell\n",
    "$ tree -L 1 cifar-10                                    \n",
    "cifar-10\n",
    "├── sampleSubmission.csv\n",
    "├── test\n",
    "├── train\n",
    "└── trainLabels.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-25T06:54:07.496010900Z",
     "start_time": "2024-07-25T06:54:07.256405800Z"
    },
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:14.056608Z",
     "iopub.status.busy": "2025-01-24T02:03:14.056137Z",
     "iopub.status.idle": "2025-01-24T02:03:16.256064Z",
     "shell.execute_reply": "2025-01-24T02:03:16.255539Z",
     "shell.execute_reply.started": "2025-01-24T02:03:14.056583Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(PosixPath('competitions/cifar-10/train/1.png'), 'frog'),\n",
      " (PosixPath('competitions/cifar-10/train/2.png'), 'truck'),\n",
      " (PosixPath('competitions/cifar-10/train/3.png'), 'truck'),\n",
      " (PosixPath('competitions/cifar-10/train/4.png'), 'deer'),\n",
      " (PosixPath('competitions/cifar-10/train/5.png'), 'automobile')]\n",
      "[(PosixPath('competitions/cifar-10/test/1.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/2.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/3.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/4.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/5.png'), 'cat')]\n",
      "50000 300000\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "DATA_DIR = Path(\".\")\n",
    "DATA_DIR1 =Path(\"competitions/cifar-10/\")\n",
    "train_lables_file = DATA_DIR / \"trainLabels.csv\"\n",
    "test_csv_file = DATA_DIR / \"sampleSubmission.csv\" #测试集模板csv文件\n",
    "train_folder = DATA_DIR1 / \"train\"\n",
    "test_folder = DATA_DIR1 / \"test\"\n",
    "\n",
    "#所有的类别\n",
    "class_names = [\n",
    "    'airplane',\n",
    "    'automobile',\n",
    "    'bird',\n",
    "    'cat',\n",
    "    'deer',\n",
    "    'dog',\n",
    "    'frog',\n",
    "    'horse',\n",
    "    'ship',\n",
    "    'truck',\n",
    "]\n",
    "\n",
    "def parse_csv_file(filepath, folder):\n",
    "    \"\"\"Parses csv files into (filename(path), label) format\"\"\"\n",
    "    results = []\n",
    "    #读取所有行\n",
    "    with open(filepath, 'r') as f:\n",
    "#         lines = f.readlines()  为什么加[1:]，可以试这个\n",
    "        #第一行不需要，因为第一行是标签\n",
    "        lines = f.readlines()[1:] \n",
    "    for line in lines:#依次去取每一行\n",
    "        image_id, label_str = line.strip('\\n').split(',')\n",
    "        image_full_path = folder / f\"{image_id}.png\"\n",
    "        results.append((image_full_path, label_str)) #得到对应图片的路径和分类\n",
    "    return results\n",
    "\n",
    "#解析对应的文件夹\n",
    "train_labels_info = parse_csv_file(train_lables_file, train_folder)\n",
    "test_csv_info = parse_csv_file(test_csv_file, test_folder)\n",
    "#打印\n",
    "import pprint\n",
    "pprint.pprint(train_labels_info[0:5])\n",
    "pprint.pprint(test_csv_info[0:5])\n",
    "print(len(train_labels_info), len(test_csv_info))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:18.061315Z",
     "iopub.status.busy": "2025-01-24T02:03:18.060973Z",
     "iopub.status.idle": "2025-01-24T02:03:18.120787Z",
     "shell.execute_reply": "2025-01-24T02:03:18.120232Z",
     "shell.execute_reply.started": "2025-01-24T02:03:18.061293Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                            filepath       class\n",
      "0  competitions/cifar-10/train/1.png        frog\n",
      "1  competitions/cifar-10/train/2.png       truck\n",
      "2  competitions/cifar-10/train/3.png       truck\n",
      "3  competitions/cifar-10/train/4.png        deer\n",
      "4  competitions/cifar-10/train/5.png  automobile\n",
      "                                filepath       class\n",
      "0  competitions/cifar-10/train/45001.png       horse\n",
      "1  competitions/cifar-10/train/45002.png  automobile\n",
      "2  competitions/cifar-10/train/45003.png        deer\n",
      "3  competitions/cifar-10/train/45004.png  automobile\n",
      "4  competitions/cifar-10/train/45005.png    airplane\n",
      "                           filepath class\n",
      "0  competitions/cifar-10/test/1.png   cat\n",
      "1  competitions/cifar-10/test/2.png   cat\n",
      "2  competitions/cifar-10/test/3.png   cat\n",
      "3  competitions/cifar-10/test/4.png   cat\n",
      "4  competitions/cifar-10/test/5.png   cat\n"
     ]
    }
   ],
   "source": [
    "# train_df = pd.DataFrame(train_labels_info)\n",
    "train_df = pd.DataFrame(train_labels_info[0:45000])\n",
    "valid_df = pd.DataFrame(train_labels_info[45000:])\n",
    "test_df = pd.DataFrame(test_csv_info)\n",
    "\n",
    "train_df.columns = ['filepath', 'class']\n",
    "valid_df.columns = ['filepath', 'class']\n",
    "test_df.columns = ['filepath', 'class']\n",
    "\n",
    "print(train_df.head())\n",
    "print(valid_df.head())\n",
    "print(test_df.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:19.722408Z",
     "iopub.status.busy": "2025-01-24T02:03:19.722048Z",
     "iopub.status.idle": "2025-01-24T02:03:21.896802Z",
     "shell.execute_reply": "2025-01-24T02:03:21.896273Z",
     "shell.execute_reply.started": "2025-01-24T02:03:19.722385Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from PIL import Image\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "from torchvision import transforms\n",
    "\n",
    "class Cifar10Dataset(Dataset):\n",
    "    df_map = {\n",
    "        \"train\": train_df,\n",
    "        \"eval\": valid_df,\n",
    "        \"test\": test_df\n",
    "    }\n",
    "    label_to_idx = {label: idx for idx, label in enumerate(class_names)} #将类别转换为数字\n",
    "    idx_to_label = {idx: label for idx, label in enumerate(class_names)}#将数字转换为类别\n",
    "    def __init__(self, mode, transform=None):\n",
    "        self.df = self.df_map.get(mode, None)\n",
    "        if self.df is None:\n",
    "            raise ValueError(\"mode should be one of train, val, test, but got {}\".format(mode))\n",
    "\n",
    "        self.transform = transform #对图片进行变换，transform是一个函数\n",
    "        \n",
    "    def __getitem__(self, index):\n",
    "        img_path, label = self.df.iloc[index]#得到对应的图片路径和类别\n",
    "        img = Image.open(img_path).convert('RGB')#打开图片\n",
    "        # # img 转换为 channel first\n",
    "        # img = img.transpose((2, 0, 1))\n",
    "        # transform\n",
    "        img = self.transform(img) #对图片进行变换\n",
    "        # label 转换为 idx\n",
    "        label = self.label_to_idx[label]\n",
    "        return img, label #返回图片和类别\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self.df.shape[0]\n",
    "    \n",
    "IMAGE_SIZE = 32\n",
    "mean, std = [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261]\n",
    "\n",
    "transforms_train = transforms.Compose([\n",
    "        # resize\n",
    "        transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),\n",
    "        # random rotation 40\n",
    "        transforms.RandomRotation(40),\n",
    "        # horizaontal flip\n",
    "        transforms.RandomHorizontalFlip(),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize(mean, std)\n",
    "    ])\n",
    "\n",
    "transforms_eval = transforms.Compose([\n",
    "        # resize\n",
    "        transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize(mean, std)\n",
    "    ])\n",
    "\n",
    "train_ds = Cifar10Dataset(\"train\", transforms_train)\n",
    "eval_ds = Cifar10Dataset(\"eval\", transforms_eval) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:26.087046Z",
     "iopub.status.busy": "2025-01-24T02:03:26.086587Z",
     "iopub.status.idle": "2025-01-24T02:03:26.090553Z",
     "shell.execute_reply": "2025-01-24T02:03:26.090037Z",
     "shell.execute_reply.started": "2025-01-24T02:03:26.087022Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "batch_size = 64\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, num_workers=4)   \n",
    "eval_dl = DataLoader(eval_ds, batch_size=batch_size, shuffle=False, num_workers=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-23T01:47:10.694223Z",
     "iopub.status.busy": "2025-01-23T01:47:10.694085Z",
     "iopub.status.idle": "2025-01-23T01:47:10.696438Z",
     "shell.execute_reply": "2025-01-23T01:47:10.696064Z",
     "shell.execute_reply.started": "2025-01-23T01:47:10.694209Z"
    }
   },
   "outputs": [],
   "source": [
    "# 遍历train_ds得到每张图片，计算每个通道的均值和方差\n",
    "# def cal_mean_std(ds):\n",
    "#     mean = 0.\n",
    "#     std = 0.\n",
    "#     for img, _ in ds:\n",
    "#         mean += img.mean(dim=(1, 2))\n",
    "#         std += img.std(dim=(1, 2))\n",
    "#     mean /= len(ds)\n",
    "#     std /= len(ds)\n",
    "#     return mean, std\n",
    "#\n",
    "# # 经过 normalize 后 均值为0，方差为1\n",
    "# print(cal_mean_std(train_ds))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-25T07:01:50.235242700Z",
     "start_time": "2024-07-25T07:01:50.218212400Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:28.805788Z",
     "iopub.status.busy": "2025-01-24T02:03:28.805429Z",
     "iopub.status.idle": "2025-01-24T02:03:28.841768Z",
     "shell.execute_reply": "2025-01-24T02:03:28.841198Z",
     "shell.execute_reply.started": "2025-01-24T02:03:28.805764Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             model.0.weight             paramerters num: 864\n",
      "              model.0.bias              paramerters num: 32\n",
      "             model.2.weight             paramerters num: 9216\n",
      "              model.2.bias              paramerters num: 32\n",
      "             model.5.weight             paramerters num: 9216\n",
      "              model.5.bias              paramerters num: 32\n",
      "             model.7.weight             paramerters num: 9216\n",
      "              model.7.bias              paramerters num: 32\n",
      "            model.10.weight             paramerters num: 9216\n",
      "             model.10.bias              paramerters num: 32\n",
      "            model.12.weight             paramerters num: 9216\n",
      "             model.12.bias              paramerters num: 32\n",
      "               cls.weight               paramerters num: 5120\n",
      "                cls.bias                paramerters num: 10\n"
     ]
    }
   ],
   "source": [
    "class VGG(nn.Module):\n",
    "    def __init__(self, num_classes):\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Flatten(),\n",
    "        )\n",
    "        \n",
    "        self.cls = nn.Linear(512, num_classes)\n",
    "        \n",
    "        self.init_weights()\n",
    "        \n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "                \n",
    "    @classmethod\n",
    "    def from_pretrained(cls, ckpt_path, num_classes=10):\n",
    "        state_dict = torch.load(ckpt_path, map_location=\"cpu\") #加载模型\n",
    "        state_dict.pop(\"cls.weight\") #去掉最后一层的权重\n",
    "        state_dict.pop(\"cls.bias\") #去掉最后一层的偏置\n",
    "        \n",
    "        model = cls(num_classes=num_classes) #实例化模型\n",
    "        # 将修改后的状态字典加载到新创建的模型实例中。参数strict=False表示在加载状态字典时，如果字典中存在模型不期望的键或缺少某些期望的键，将不会抛出错误。这在迁移学习中很有用，因为你可能希望覆盖或忽略一些权重。\n",
    "        model.load_state_dict(state_dict, strict=False) #加载模型参数\n",
    "\n",
    "        return model\n",
    "        \n",
    "    def forward(self, x):\n",
    "        features = self.model(x)\n",
    "        return self.cls(features)\n",
    "        \n",
    "for key, value in VGG(len(class_names)).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-25T07:09:22.216355600Z",
     "start_time": "2024-07-25T07:09:22.205361600Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:32.382607Z",
     "iopub.status.busy": "2025-01-24T02:03:32.382273Z",
     "iopub.status.idle": "2025-01-24T02:03:32.388421Z",
     "shell.execute_reply": "2025-01-24T02:03:32.387949Z",
     "shell.execute_reply.started": "2025-01-24T02:03:32.382584Z"
    },
    "jupyter": {
     "outputs_hidden": false
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'generator'>\n",
      "             model.0.weight             paramerters num: 864\n",
      "              model.0.bias              paramerters num: 32\n",
      "             model.2.weight             paramerters num: 9216\n",
      "              model.2.bias              paramerters num: 32\n",
      "             model.5.weight             paramerters num: 9216\n",
      "              model.5.bias              paramerters num: 32\n",
      "             model.7.weight             paramerters num: 9216\n",
      "              model.7.bias              paramerters num: 32\n",
      "            model.10.weight             paramerters num: 9216\n",
      "             model.10.bias              paramerters num: 32\n",
      "            model.12.weight             paramerters num: 9216\n",
      "             model.12.bias              paramerters num: 32\n",
      "               cls.weight               paramerters num: 5120\n",
      "                cls.bias                paramerters num: 10\n"
     ]
    }
   ],
   "source": [
    "model=VGG(len(class_names))\n",
    "print(type(model.named_parameters()))\n",
    "for key, value in  model.named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练\n",
    "\n",
    "pytorch的训练需要自行实现，包括\n",
    "1. 定义损失函数\n",
    "2. 定义优化器\n",
    "3. 定义训练步\n",
    "4. 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:34.113417Z",
     "iopub.status.busy": "2025-01-24T02:03:34.112971Z",
     "iopub.status.idle": "2025-01-24T02:03:34.219714Z",
     "shell.execute_reply": "2025-01-24T02:03:34.219056Z",
     "shell.execute_reply.started": "2025-01-24T02:03:34.113393Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        \n",
    "        preds = logits.argmax(axis=-1)    # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 可视化\n",
    "\n",
    "\n",
    "训练过程中可以使用如下命令启动tensorboard服务。\n",
    "\n",
    "```shell\n",
    "tensorboard \\\n",
    "    --logdir=runs \\     # log 存放路径\n",
    "    --host 0.0.0.0 \\    # ip\n",
    "    --port 8848         # 端口\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:40.297835Z",
     "iopub.status.busy": "2025-01-24T02:03:40.297366Z",
     "iopub.status.idle": "2025-01-24T02:03:40.498944Z",
     "shell.execute_reply": "2025-01-24T02:03:40.498442Z",
     "shell.execute_reply.started": "2025-01-24T02:03:40.297809Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "        \n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\", \n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "        \n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "        \n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "            \n",
    "        )\n",
    "    \n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:42.122046Z",
     "iopub.status.busy": "2025-01-24T02:03:42.121609Z",
     "iopub.status.idle": "2025-01-24T02:03:42.127189Z",
     "shell.execute_reply": "2025-01-24T02:03:42.126733Z",
     "shell.execute_reply.started": "2025-01-24T02:03:42.122023Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:43.605636Z",
     "iopub.status.busy": "2025-01-24T02:03:43.605301Z",
     "iopub.status.idle": "2025-01-24T02:03:43.609991Z",
     "shell.execute_reply": "2025-01-24T02:03:43.609504Z",
     "shell.execute_reply.started": "2025-01-24T02:03:43.605614Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:03:45.060381Z",
     "iopub.status.busy": "2025-01-24T02:03:45.060054Z",
     "iopub.status.idle": "2025-01-24T02:05:04.937143Z",
     "shell.execute_reply": "2025-01-24T02:05:04.936544Z",
     "shell.execute_reply.started": "2025-01-24T02:03:45.060359Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 7040/7040 [01:19<00:00, 88.29it/s, epoch=9] \n"
     ]
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1)\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 10\n",
    "model = VGG(num_classes=10) #第一次先训练，得到下面best.ckpt后，再注释这一条，用下面的加载模型\n",
    "\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "# Optimizers specified in the torch.optim package\n",
    "\n",
    "\n",
    "exp_name = \"vgg-fine-tune\"\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "# tensorboard_callback = TensorBoardCallback(f\"runs/{exp_name}\")\n",
    "# tensorboard_callback.draw_model(model, [1, 3, IMAGE_SIZE, IMAGE_SIZE])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "\n",
    "save_ckpt_callback = SaveCheckpointsCallback(f\"checkpoints/{exp_name}\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=5)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    eval_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:05:39.012277Z",
     "iopub.status.busy": "2025-01-24T02:05:39.011922Z",
     "iopub.status.idle": "2025-01-24T02:05:39.263765Z",
     "shell.execute_reply": "2025-01-24T02:05:39.263289Z",
     "shell.execute_reply.started": "2025-01-24T02:05:39.012252Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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n8/Pf/5zPvnkEw4dOsT69esB9SLzrLPOYtmyZWzZsgWLxcKLL744aPEPNg899BC33XYbt956K1OnTuWxxx7DbrezYsWKqOtv3LiRs846i+uvv56SkhIWLFjAddddx+bNmwc58uFHvOfIxo0bB/Uceeedd5g3bx633347p512GhMmTODAgQP686mpqZSUlLBu3bqo28+YMYOKigr27t07YDEKwkihrSN0c2/9nsSrGEYakiECRjV9wDzT67zQnjHUoQiCMMSUlJTw3nvvcejQIVJSUmLemZ44cSLPP/88ixYtQlEU7rrrrgHJ9MTiO9/5DmeeeSb3338/11xzDZs2beJ3v/sdv//97wF4+eWXOXjwIOeeey6ZmZm8+uqr+P1+Jk2axHvvvce6detYsGABeXl5bNq0ibq6Or1v4kTD7XazZcsWli5dqi8zGAzMnz+fTZs2Rd1m3rx5/OMf/2Dz5s3Mnj2bgwcP8uqrr3LjjTfGPI7L5cLlcumPW1paAPB4PF0yhx6Ph0AggN/vj/l3o5lcaOsNF8aOHct7773HwYMHSUlJ0S22tdeixT1hwgSef/55Pv3pT6MoCnfffbf+fPjr6fw42nvS3fukMWHCBJ544glee+01SktL+cc//sH7779PaWmpvu3dd9/N7bffTm5uLpdccgmtra1s3LiRxYsXc+655zJv3jyuvvpqPau1e/duFEWJ2b+kvR6PxzMk5gva31VPmenhhsQ9uPQm7raOUF/91qNNVDU5yE629Htssejre53odiKIAHdWGRyAIvfhoQ5FEIQh5s477+Tmm29m6tSptLe389e//jXqeg899BBf/OIXmTdvHjk5OXz/+9/XL4AHg9NPP51//etf3H333dx///0UFhZy3333ccsttwCQkZHB888/z7333ktHRwcTJ07kqaeeYtq0aezatYs333yThx9+WG9+v//++7n00ksHLf7BpK6uDp/PR35+fsTy/Px83RCgM9dffz11dXWcffbZ+lydr33ta/zwhz+MeZzly5dHNPVrrF69GrvdHrHMZDJRUFBAW1tbjyVkra2t3T4/2Hz1q1/l9ttvZ/r06bS3t/Poo48CapzhpX3Lli1j8eLFnH322WRlZfHNb36TxsZG3G63fq74/X46Ojoizp329vaIx4FAoMs60bj22mvZvHkz1157LYqi8H//93988Ytf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+vkxZsyYhEMzGAz85je/obS0lIMHD3L77bfzve99j9///vcAbN26lYsuuogvfvGLPPLII5hMJl5//XV8PvVO9NKlS/nzn//Mr3/9a84++2wqKyvZvVuqQAShO6LZbkPiJXNH6p0R91uanB6K45/UM6j0aQ7RiYTVoP7GqqwlqiCq2SWCSBBOQjIzM7n00kt58skn9Qu+Z599lpycHC644AIMBgMzZ87U17///vt54YUXeOmll7j99tv7dOwnn3ySjo4OnnjiCZKT1S+e3/3udyxatIif/exnmM1mmpubufzyyxk/fjwAU6ZM0bc/cuQI3/3ud5k8eTIAEyeOnPEBwsggnvNjxowZtLS0kJaWFnF+LF68OOHjhRsvlJSU8MADD/C1r31NF0Q///nPOeOMM/THANOmTQNUG/lHHnmE3/3ud9x8882Aanhy9tln9/blC8JJgcPd1VQBoCRYMlfb6qK1w0Oqrfsbbp2FU6PzBMkQnchYg3bqFaaxTOI9qJU7SILQr5jt6p3oOPD7/bS0tpKWmto/LnPmxOaT3XDDDdx22238/ve/x2q18s9//pNrr70Wg8FAW1sb9957L6+88gqVlZV4vV7a29s5cuRIn8PctWsXM2fO1MUQwFlnnYXf72fPnj2ce+653HLLLSxcuJCLL76Y+fPn8/nPf143oFmyZAlf/vKX+fvf/878+fO5+uqrdeEkjAA6nSP9fh50d9wE6On8uOeee3j55Zeprq7u8/mxdu1ali9fzu7du2lpacHr9dLR0YHT6cRut7N161auvvrqqNvu2rULl8sV1a1WEITYtMXIEKUnmclJsVDX5uZwvZPpRend7mckCaKR42c7wGiC6JAxmNKvEac5QehXFEUty4n3x2xPbP3ufhKcCbRo0SICgQCvvPIKR48e5a233uKGG24A4M477+SFF17gwQcf5K233mLr1q3MmDGj18NnE+Wvf/0rmzZtYt68eTzzzDOUlZXx7rvvAnDvvfeyY8cOPv3pT7N+/XqmTp3KCy+8MChxCf1AtHOkP8+DQTo/XnzxRe666y7eeOONPp0fhw4d4vLLL+eUU07hueeeY8uWLTz66KMA+v6SkpJibt/dc4IgxKYthsschMrmDsZRNtdZEDUNY+ttEURBNEF0UClW/yMZIkE4abHZbHz2s5/ln//8J0899RSTJk3i9NPVCdvvvPMOt9xyC1dddRUzZsygoKCgx17JeJkyZQoff/wxDkfoS+Sdd97BYDAwadIkfdlpp53G0qVL2bhxI9OnT+fJJ5/UnysrK+Pb3/42q1ev5rOf/Sx//etf+yU2QdDo6fy4+eabufzyy/t8fmzZsgW/38+vfvUrPvWpT1FWVkZFRWSW+ZRTTmHdunVRt584cSJJSUkxnxcEITrdCaJEnOY0QaTtRwTRCMAafCf2+TWnuWpwNgxdQIIgDCk33HADr7zyCitWrNDvfoN6kfX888+zdetWPv74Y66//voujlt9OabNZuPmm29m+/btvP7663zjG9/gxhtvJD8/n/LycpYuXcqmTZs4fPgwq1evZt++fUyZMoX29nYWL17Mhg0bOHz4MO+88w7vv/9+RI+RIPQX3Z0fL7zwAtu2bevz+TFhwgQ8Hg+//e1vOXjwIH//+9957LHHItZZunQp77//PrfffjuffPIJu3fv5g9/+AN1dXXYbDa+//3v873vfY8nnniCAwcO8O677/L444/36bULwomMx+enw6Oes1EFUdBp7lAcTnOaIJpZrJbWScncCEDLENV5LJAuWSJBONm58MILycrKYs+ePVx//fX68oceeojMzEzmzZvHokWLWLhwoX53vK/Y7Xb+97//0dDQwJlnnsnnPvc5LrroIn73u9/pz+/evZv/+7//o6ysjK985SvccccdfPWrX8VoNFJfX89NN91EWVkZn//857n00ktZtmxZv8QmCOH0dH4sXLiQK664ok/nx8yZM3nooYf42c9+xvTp0/nnP//J8uXLI9YpKytj9erVfPzxx8yePZu5c+fyn//8B5NJvZC76667+M53vsPdd9/NlClTuOaaa6ipqen9CxeEExxtKCt0td0GKI2zZM7h8lLT6gLg9DGZgDqcdbgipgpBrEbVZc7p8kLxZGg+qvYRjZ03xJEJgjAUGAyGLuU5oDpdrV+/PmLZHXfcAaDfCT948GDcTfCdxxnMmDGjy/418vPzY/YEWSwWnnrqqbiOKQh9pbvzY+3atbrLnMFg0M8PjURK6L797W/z7W9/O2LZjTfeGPH4vPPO45133okZ549+9CN+9KMfxX1MQTiZ0crlrCYDFlPX7zEtQ1Re20YgENDHPnRGyw5lJVsYk6UatzRKydzwR8sQOdw+yFMtayVDJAiCIAiCIJwsaIIo1RY9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3/8O6Jgjueeee1AUhW9/+9sDOvaf/OQnKIoS9jF58uQBHTPAqVOn+NKXvkROTg7JyclMnz6dLVu2GNcPxN/J4uLido+1oijceuutwMB9rEXH5LkpPvLc1H+/v4nyvATy3CTPTVGoQ9zzzz+v2mw29YknnlB3796t3nTTTWpmZqZaUVHRJ19/3bp16o9+9CP1xRdfVAH1n//8Z9j199xzj5qRkaG+9NJL6scff6x+9rOfVceMGaO2tLQYx1x22WXqzJkz1Q8++EB955131PHjx6vXXnutcX19fb2an5+vXnfddequXbvU5557Tk1OTlb/8Ic/dCnmpUuXqk8++aS6a9cudceOHery5cvVUaNGqY2NjcYxN998szpy5Eh1w4YN6pYtW9RPfepT6rnnnmtc7/V61bPOOktdtGiRun37dnXdunVqbm6uumbNGuOYI0eOqA6HQ129erW6Z88e9cEHH1TNZrO6fv36LsX9r3/9S33llVfUAwcOqPv371d/+MMfqlarVd21a9eAjbmtzZs3q8XFxeqMGTPUb33rW8blAzH2O++8U502bZpaVlZmfFRVVQ3omGtqatTRo0erN954o/rhhx+qR44cUV999VX10KFDxjED8XeysrIy7HEuKSlRAfXNN99UVXVgPtaiY/LcFD95buqf399Eel5SVXlukuemyIZ8QjRv3jz11ltvNT73+XxqUVGRunbt2j6Ppe2Tjt/vVwsKCtRf//rXxmV1dXWq3W5Xn3vuOVVVVXXPnj0qoH700UfGMf/9739VRVHUU6dOqaqqqr///e/VrKws1eVyGcfcfvvt6qRJk3ok7srKShVQ33rrLSNGq9Wq/u1vfzOO2bt3rwqomzZtUlVVe7I1mUxqeXm5cczDDz+spqenG3F+//vfV6dNmxb2tVasWKEuXbq0R+JWVVXNyspSH3vssYSIuaGhQZ0wYYJaUlKiXnjhhcYTz0CN/c4771RnzpwZ8bqBGvPtt9+unnfeeVGvT5TfyW9961vquHHjVL/fP2Afa9ExeW7qPnlu6v2YE+15SVXluUmemyIb0kvm3G43W7duZdGiRcZlJpOJRYsWsWnTpn6MTHP06FHKy8vD4svIyGD+/PlGfJs2bSIzM5O5c+caxyxatAiTycSHH35oHHPBBRdgs9mMY5YuXcr+/fupra3tdpz19fUAZGdnA7B161Y8Hk9Y3JMnT2bUqFFhcU+fPp38/PywmJxOJ7t37zaOCT2HfkxPfG98Ph/PP/88TU1NLFiwICFivvXWW7n88svbnX8gx37w4EGKiooYO3Ys1113HaWlpQM65n/961/MnTuXL37xi+Tl5TF79mweffRR4/pE+J10u90888wzfOUrX0FRlAH7WIvo5LlJnpsS5bkpEZ+XQJ6bdPLcFDSkE6Lq6mp8Pl/YAw2Qn59PeXl5P0UVpMfQUXzl5eXk5eWFXW+xWMjOzg47JtI5Qr9GV/n9fr797W+zcOFCzjrrLOOcNpuNzMzMDuPuLKZoxzidTlpaWroU7yeffEJqaip2u52bb76Zf/7zn0ydOnVAxwzw/PPPs23bNtauXdvuuoEa+/z583nqqadYv349Dz/8MEePHuX888+noaFhwMZ85MgRHn74YSZMmMCrr77KLbfcwv/93//x9NNPh33dgfw7+dJLL1FXV8eNN95onG8gPtYiOnlukuemRHhuSsTnJZDnplDy3BRkiefOCNHWrbfeyq5du3j33Xf7O5SYTJo0iR07dlBfX8/f//53brjhBt56663+DqtDJ06c4Fvf+hYlJSUkJSX1dzgxW7ZsmfH/GTNmMH/+fEaPHs1f//pXkpOT+zGy6Px+P3PnzuUXv/gFALNnz2bXrl088sgj3HDDDf0cXWwef/xxli1bRlFRUX+HIkS/keem3pWoz0sgz039ZaA/Nw3pClFubi5ms7ldR4uKigoKCgr6KaogPYaO4isoKKCysjLseq/XS01NTdgxkc4R+jW6YtWqVfznP//hzTffZMSIEWFxu91u6urqOoy7s5iiHZOent7lP1o2m43x48czZ84c1q5dy8yZM/ntb387oGPeunUrlZWVnH322VgsFiwWC2+99Ra/+93vsFgs5OfnD9jYQ2VmZjJx4kQOHTo0YB/vwsJCpk6dGnbZlClTjOUUA/138vjx47z++ut87WtfMy4bqI+1iE6em+S5aaA/Nw2W5yWQ5yZ5btIM6YTIZrMxZ84cNmzYYFzm9/vZsGEDCxYs6MfINGPGjKGgoCAsPqfTyYcffmjEt2DBAurq6ti6datxzBtvvIHf72f+/PnGMW+//TYej8c4pqSkhEmTJpGVlRV3XKqqsmrVKv75z3/yxhtvMGbMmLDr58yZg9VqDYt7//79lJaWhsX9ySefhP1ylpSUkJ6ebvzSL1iwIOwc+jE9+b3x+/24XK4BHfOll17KJ598wo4dO4yPuXPnct111xn/H6ixh2psbOTw4cMUFhYO2Md74cKF7dr0HjhwgNGjRwMD93dS9+STT5KXl8fll19uXDZQH2sRnTw3yXPTQH9uGizPSyDPTfLcFNC1PhGDx/PPP6/a7Xb1qaeeUvfs2aN+/etfVzMzM8M6WvSmhoYGdfv27er27dtVQL3//vvV7du3q8ePH1dVVWujmJmZqb788svqzp071SuuuCJiG8XZs2erH374ofruu++qEyZMCGujWFdXp+bn56tf/vKX1V27dqnPP/+86nA4utxG8ZZbblEzMjLUjRs3hrVTbG5uNo65+eab1VGjRqlvvPGGumXLFnXBggXqggULjOv1VopLlixRd+zYoa5fv14dNmxYxFaKt912m7p37171oYce6lbbyh/84AfqW2+9pR49elTduXOn+oMf/EBVFEV97bXXBmzM0YR28xmosX/3u99VN27cqB49elR977331EWLFqm5ublqZWXlgI158+bNqsViUX/+85+rBw8eVJ999lnV4XCozzzzjHHMQPydVFWtC9moUaPU22+/vd11A/GxFh2T56b4yXNT//7+JsLzkqrKc5M8N0U25BMiVVXVBx98UB01apRqs9nUefPmqR988EGffe0333xTBdp93HDDDaqqaq0Uf/zjH6v5+fmq3W5XL730UnX//v1h5zhz5ox67bXXqqmpqWp6erq6cuVKtaGhIeyYjz/+WD3vvPNUu92uDh8+XL3nnnu6HHOkeAH1ySefNI5paWlRv/GNb6hZWVmqw+FQr7rqKrWsrCzsPMeOHVOXLVumJicnq7m5uep3v/td1ePxtHt8Zs2apdpsNnXs2LFhXyNeX/nKV9TRo0erNptNHTZsmHrppZcaTzgDNeZo2j7xDMTYV6xYoRYWFqo2m00dPny4umLFirCZCQMxZlVV1X//+9/qWWedpdrtdnXy5MnqH//4x7DrB+LvpKqq6quvvqoC7WJR1YH7WIuOyXNTfOS5qX9/fxPheUlV5blJnpsiU1RVVeOrKQkhhBBCCCHE4DCk9xAJIYQQQgghhjZJiIQQQgghhBBDliREQgghhBBCiCFLEiIhhBBCCCHEkCUJkRBCCD/3SSgAAAQMSURBVCGEEGLIkoRICCGEEEIIMWRJQiSEEEIIIYQYsiQhEkIIIYQQQgxZkhAJ0UduvPFGrrzyyv4OQwghhDDIc5MQkhAJIYQQQgghhjBJiIToYX//+9+ZPn06ycnJ5OTksGjRIm677TaefvppXn75ZRRFQVEUNm7cCMCJEye4+uqryczMJDs7myuuuIJjx44Z59PfvbvrrrsYNmwY6enp3Hzzzbjd7v65g0IIIRKOPDcJEZ2lvwMQYjApKyvj2muv5Ve/+hVXXXUVDQ0NvPPOO1x//fWUlpbidDp58sknAcjOzsbj8bB06VIWLFjAO++8g8Vi4e677+ayyy5j586d2Gw2ADZs2EBSUhIbN27k2LFjrFy5kpycHH7+85/3590VQgiRAOS5SYiOSUIkRA8qKyvD6/Xyuc99jtGjRwMwffp0AJKTk3G5XBQUFBjHP/PMM/j9fh577DEURQHgySefJDMzk40bN7JkyRIAbDYbTzzxBA6Hg2nTpvHTn/6U2267jZ/97GeYTFLoFUIIEZ08NwnRMflpFaIHzZw5k0svvZTp06fzxS9+kUcffZTa2tqox3/88cccOnSItLQ0UlNTSU1NJTs7m9bWVg4fPhx2XofDYXy+YMECGhsbOXHiRK/eHyGEEIlPnpuE6JhUiIToQWazmZKSEt5//31ee+01HnzwQX70ox/x4YcfRjy+sbGROXPm8Oyzz7a7btiwYb0drhBCiCFAnpuE6JgkREL0MEVRWLhwIQsXLuSOO+5g9OjR/POf/8Rms+Hz+cKOPfvss3nhhRfIy8sjPT096jk//vhjWlpaSE5OBuCDDz4gNTWVkSNH9up9EUIIMTjIc5MQ0cmSOSF60IcffsgvfvELtmzZQmlpKS+++CJVVVVMmTKF4uJidu7cyf79+6mursbj8XDdddeRm5vLFVdcwTvvvMPRo0fZuHEj//d//8fJkyeN87rdbr761a+yZ88e1q1bx5133smqVatkjbYQQohOyXOTEB2TCpEQPSg9PZ23336bBx54AKfTyejRo7nvvvtYtmwZc+fOZePGjcydO5fGxkbefPNNLrroIt5++21uv/12Pve5z9HQ0MDw4cO59NJLw96Vu/TSS5kwYQIXXHABLpeLa6+9lp/85Cf9d0eFEEIkDHluEqJjiqqqan8HIYSI7sYbb6Suro6XXnqpv0MRQgghAHluEoOL1DSFEEIIIYQQQ5YkREIIIYQQQoghS5bMCSGEEEIIIYYsqRAJIYQQQgghhixJiIQQQgghhBBDliREQgghhBBCiCFLEiIhhBBCCCHEkCUJkRBCCCGEEGLIkoRICCGEEEIIMWRJQiSEEEIIIYQYsiQhEkIIIYQQQgxZkhAJIYQQQgghhqz/H396y/8mCWsMAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=100)  #横坐标是 steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:05:41.560203Z",
     "iopub.status.busy": "2025-01-24T02:05:41.559862Z",
     "iopub.status.idle": "2025-01-24T02:05:42.290120Z",
     "shell.execute_reply": "2025-01-24T02:05:42.289388Z",
     "shell.execute_reply.started": "2025-01-24T02:05:41.560180Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_332/3500857114.py:4: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
      "  model.load_state_dict(torch.load(f\"checkpoints/{exp_name}/best.ckpt\", map_location=\"cpu\"))\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.8424\n",
      "accuracy: 0.7090\n"
     ]
    }
   ],
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(f\"checkpoints/{exp_name}/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, eval_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:06:22.716269Z",
     "iopub.status.busy": "2025-01-24T02:06:22.715916Z",
     "iopub.status.idle": "2025-01-24T02:07:38.898825Z",
     "shell.execute_reply": "2025-01-24T02:07:38.898260Z",
     "shell.execute_reply.started": "2025-01-24T02:06:22.716245Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_332/1443937527.py:36: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
      "  state_dict = torch.load(ckpt_path, map_location=\"cpu\") #加载模型\n",
      "100%|██████████| 7040/7040 [01:16<00:00, 92.43it/s, epoch=9] \n"
     ]
    }
   ],
   "source": [
    "model = VGG.from_pretrained(\"checkpoints/vgg-fine-tune/best.ckpt\", num_classes=10)\n",
    "# 微调（Fine-tuning）：在迁移学习或微调预训练模型时，这种方法特别有用。在这种情况下，你可能希望对模型的预训练部分（不包含\"cls\"的部分）使用较小的学习率，以避免破坏已经学到的特征。而对新添加的或需要特别训练的部分（如新的分类层，包含\"cls\"的部分）使用较高的学习率，以便更快地学习到特定任务的特征。\n",
    "optimizer = torch.optim.Adam(\n",
    "    [\n",
    "        {\n",
    "            \"params\": [value for key, value in model.named_parameters() if \"cls\" not in key],\n",
    "            \"lr\": 0.0001 #卷积层用的是之前的预训练参数，不希望变化过大，所以学习率设为较小\n",
    "        },\n",
    "        {\n",
    "            \"params\": [value for key, value in model.named_parameters() if \"cls\" in key],\n",
    "            \"lr\": 0.0005 #分类层是重新初始化的，可以用较大的学习率\n",
    "        },\n",
    "     ]\n",
    "    )\n",
    "early_stop_callback = EarlyStopCallback(patience=5)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    eval_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-24T02:07:47.206296Z",
     "iopub.status.busy": "2025-01-24T02:07:47.205930Z",
     "iopub.status.idle": "2025-01-24T02:07:47.878298Z",
     "shell.execute_reply": "2025-01-24T02:07:47.877551Z",
     "shell.execute_reply.started": "2025-01-24T02:07:47.206270Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_332/421157305.py:1: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
      "  model.load_state_dict(torch.load(f\"checkpoints/{exp_name}/best.ckpt\", map_location=\"cpu\"))\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.7288\n",
      "accuracy: 0.7524\n"
     ]
    }
   ],
   "source": [
    "model.load_state_dict(torch.load(f\"checkpoints/{exp_name}/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, eval_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 推理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-23T01:49:39.074976Z",
     "iopub.status.busy": "2025-01-23T01:49:39.074738Z",
     "iopub.status.idle": "2025-01-23T01:49:39.077579Z",
     "shell.execute_reply": "2025-01-23T01:49:39.077000Z",
     "shell.execute_reply.started": "2025-01-23T01:49:39.074948Z"
    }
   },
   "outputs": [],
   "source": [
    "# test_df\n",
    "# test_ds = Cifar10Dataset(\"test\", transform=transforms_eval)\n",
    "# test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, drop_last=False)\n",
    "#\n",
    "# preds_collect = []\n",
    "# model.eval()\n",
    "# for data, fake_label in tqdm(test_dl):\n",
    "#     data = data.to(device=device)\n",
    "#     logits = model(data)\n",
    "#     preds = [test_ds.idx_to_label[idx] for idx in logits.argmax(axis=-1).cpu().tolist()]\n",
    "#     preds_collect.extend(preds)\n",
    "#\n",
    "# test_df[\"class\"] = preds_collect\n",
    "# test_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-23T01:49:39.078596Z",
     "iopub.status.busy": "2025-01-23T01:49:39.078226Z",
     "iopub.status.idle": "2025-01-23T01:49:39.081097Z",
     "shell.execute_reply": "2025-01-23T01:49:39.080596Z",
     "shell.execute_reply.started": "2025-01-23T01:49:39.078568Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 导出 submission.csv\n",
    "# test_df.to_csv(\"submission.csv\", index=False)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
